from aiogram import Router, types, F
from aiogram.fsm.context import FSMContext
from loguru import logger as log

from database import models
from tg_bot.filters.user_filter import IsAdmin
from tg_bot.keyboards import inline, callback_factory
from tg_bot.services.text import not_correct_input
from tg_bot.states.admin import AdminCmd, AdminCategory

CATEGORY_TEXT = 'Меню категорий: '


dp = Router()
dp.message.filter(IsAdmin(is_admin=True))
dp.callback_query.filter(IsAdmin())


async def admin_category_message(message: types.Message, state: FSMContext):
    data = await state.get_data()
    current_page = data.get('CategoryPaginator_page', 1)
    key = inline.CategoryPaginator(
        dp,
        current_page=current_page,
        before_pagination_keyboards=[await inline.find_keyboard('Категория', 'category')],
        after_pagination_keyboards=[await inline.back('admin_menu')]
    )
    await message.answer(CATEGORY_TEXT, reply_markup=key.as_markup())
    await state.set_state(AdminCategory.main)


@dp.callback_query(callback_factory.AdminMenuCall.filter(
    F.item == 'category'
), AdminCmd.main)
@dp.callback_query(callback_factory.ActionCall.filter(
    F.action == 'cancel'
), AdminCategory.add)
@dp.callback_query(callback_factory.BackCall.filter(F.to == 'category_menu'), AdminCategory.info)
async def admin_category_menu(call: types.CallbackQuery, state: FSMContext):
    await admin_category_message(call.message, state)


@dp.callback_query(callback_factory.AdminActionCall.filter(
    F.action == 'add_category'
), AdminCategory.main)
async def add_category_call(call: types.CallbackQuery, state: FSMContext):
    text = 'Введите название категории: '
    key = await inline.cancel()
    try:
        await call.message.edit_text(text, reply_markup=key)
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key)
    await state.set_state(AdminCategory.add)


@dp.message(AdminCategory.add)
async def add_new_category(message: types.Message, state: FSMContext):
    if models.Category.objects.filter(name=message.text).first():
        await not_correct_input(message, 'Категория с таким названием уже имеется.')
    else:
        models.Category.objects.create(name=message.text)
        await admin_category_message(message, state)


@dp.message(F.text.startswith('CATEGORY'), F.via_bot, AdminCategory.main)
async def category_info_inline(message: types.Message, state: FSMContext):
    category_pk = int(message.text.replace('CATEGORY ', ''))
    category = models.Category.objects.filter(pk=category_pk).first()
    text = category.get_name()
    data = await state.get_data()
    current_page = data.get('ProductPaginator_page', 1)
    key = inline.ProductPaginator(
        dp,
        current_page=current_page,
        category=category,
        before_pagination_keyboards=[
            await inline.category_settings(),
            await inline.add_product()
        ],
        after_pagination_keyboards=[await inline.back('category_menu')]
    )
    await message.answer(text, reply_markup=key.as_markup())
    await state.set_state(AdminCategory.info)
    await state.update_data({'category': category})


@dp.callback_query(callback_factory.CategoryCall.filter(), AdminCategory.main)
async def category_info(call: types.CallbackQuery, state: FSMContext,
                        callback_data: callback_factory.CategoryCall):
    category = models.Category.objects.filter(pk=callback_data.pk).first()
    text = category.get_name()
    data = await state.get_data()
    current_page = data.get('ProductPaginator_page', 1)
    key = inline.ProductPaginator(
        dp,
        current_page=current_page,
        category=category,
        before_pagination_keyboards=[
            await inline.category_settings(),
            await inline.add_product()
        ],
        after_pagination_keyboards=[await inline.back('category_menu')]
    )
    try:
        await call.message.edit_text(text, reply_markup=key.as_markup())
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key.as_markup())
    await state.set_state(AdminCategory.info)
    await state.update_data({'category': category})


@dp.callback_query(callback_factory.AdminActionCall.filter(
    F.action == 'change_category_name'
), AdminCategory.info)
@dp.callback_query(callback_factory.AdminActionCall.filter(
    F.action == 'change_category_desc'
), AdminCategory.info)
async def change_category_call(call: types.CallbackQuery, state: FSMContext,
                               callback_data: callback_factory.AdminActionCall):
    match callback_data.action:
        case 'change_category_name':
            text = 'Введите новое название: '
            await state.set_state(AdminCategory.change_name)
        case _:
            text = 'Введите новое описание: '
            await state.set_state(AdminCategory.change_desc)
    key = await inline.cancel()
    try:
        await call.message.edit_text(text, reply_markup=key)
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key)


@dp.callback_query(callback_factory.ActionCall.filter(F.action == 'cancel'), AdminCategory.change_desc)
@dp.callback_query(callback_factory.ActionCall.filter(F.action == 'cancel'), AdminCategory.change_name)
async def cancel_category_change(call: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    category: models.Category = data.get('category')
    callback_data = callback_factory.CategoryCall(pk=category.pk)
    await category_info(call, state, callback_data)


@dp.message(AdminCategory.change_desc)
@dp.message(AdminCategory.change_name)
async def change_category_message(message: types.Message, state: FSMContext):
    data = await state.get_data()
    category: models.Category = data.get('category')
    match await state.get_state():
        case AdminCategory.change_name:
            if models.Category.objects.filter(name=message.text).first():
                return await not_correct_input(message, 'Категория с таким названием уже существует.')
            else:
                category.name = message.text
        case _:
            category.description = message.text
    category.save()
    text = category.get_name()
    data = await state.get_data()
    current_page = data.get('ProductPaginator_page', 1)
    key = inline.ProductPaginator(
        dp,
        current_page=current_page,
        category=category,
        before_pagination_keyboards=[
            await inline.category_settings(),
            await inline.add_product()
        ],
        after_pagination_keyboards=[await inline.back('category_menu')]
    )
    await message.answer(text, reply_markup=key.as_markup())
    await state.set_state(AdminCategory.info)


@dp.callback_query(callback_factory.AdminActionCall.filter(
    F.action == 'change_category_display'
), AdminCategory.info)
async def change_category_display(call: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    category: models.Category = data.get('category')
    category.is_visible = False if category.is_visible else True
    category.save()
    await category_info(call, state, callback_factory.CategoryCall(pk=category.pk))
